package com.zhi.syc.data_applist.services;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.location.Priority;
import com.google.android.gms.tasks.CancellationToken;
import com.google.android.gms.tasks.OnTokenCanceledListener;
import com.google.android.gms.tasks.Task;
import com.zhi.syc.data_applist.beans.ASLocationInfoBean;
import com.zhi.syc.data_applist.util.ASUtil;

import java.util.List;
import java.util.Locale;

@SuppressLint("StaticFieldLeak")
public class ASLocationInfoGms {
    private static final String TAG = "ASLocationInfoGms";

    private static final ASLocationInfoGms instance = new ASLocationInfoGms();

    private static LocationManager mLocationManager;

    private static Location mLocation = null;

    private FusedLocationProviderClient mFusedLocationClient;

    private OnLocationDidFetchedListener mOnLocationDidFetchedListener;

    private Context mContext;

    private String mToken;

    private final Handler mHandler = new Handler(Looper.getMainLooper());

    private final Runnable mGetCurrentLocationRunable = new Runnable() {
        @Override
        public void run() {
            getCurrentLocation(mContext);
        }
    };

    private final Runnable mGetLastLocationRunable = new Runnable() {
        @Override
        public void run() {
            getLastLocation(mContext);
        }
    };

    public ASLocationInfoGms() {
    }

    public static ASLocationInfoGms getInstance() {
        return instance;
    }

    public void startLocationMonitor(Context context, String token) {
        this.mToken = token;
        this.mContext = context;
        if (context == null) {
            return;
        }
        if (mFusedLocationClient == null) {
            mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
        }

        try {
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            getCurrentLocation(context);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void getCurrentLocation(Context context) {
        try {
            if (context == null) {
                return;
            }
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }

            Task<Location> locationTask = mFusedLocationClient.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, mCurrentLocationRequestToken);
            locationTask.addOnFailureListener(e -> {
                reGetLastLocationAfter2000Millis();
            });
            locationTask.addOnCompleteListener(task -> {
                try {
                    if (task.isSuccessful()) {
                        Location location = task.getResult();
                        if (location != null) {
                            AsyncTask<Location, Void, Address> locaTask = new GetAddressTask();
                            locaTask.execute(location);
                        }else {
                            reGetLastLocationAfter2000Millis();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    reGetLastLocationAfter2000Millis();
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
            reGetLastLocationAfter2000Millis();
        }
    }

    private void getLastLocation(Context context) {
        try {
            if (context == null) {
                return;
            }
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }

            Task<Location> locationTask = mFusedLocationClient.getLastLocation();
            locationTask.addOnFailureListener(e -> {
                reGetCurrentLocationAfter2000Millis();
            });
            locationTask.addOnCompleteListener(task -> {
                try {
                    if (task.isSuccessful()) {
                        Location location = task.getResult();
                        if (location != null) {
                            AsyncTask<Location, Void, Address> locaTask = new GetAddressTask();
                            locaTask.execute(location);
                        } else {
                            reGetCurrentLocationAfter2000Millis();
                        }
                    } else {
                        reGetCurrentLocationAfter2000Millis();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    reGetCurrentLocationAfter2000Millis();
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
            reGetCurrentLocationAfter2000Millis();
        }
    }

    public void setOnLocationDidFetchedListener(OnLocationDidFetchedListener listener) {
        this.mOnLocationDidFetchedListener = listener;
    }

    private List<Address> getAddress(Location location) {
        List<Address> result = null;
        try {
            if (location != null) {
                Geocoder gc = new Geocoder(mContext, Locale.getDefault());
                result = gc.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    private final CancellationToken mCurrentLocationRequestToken = new CancellationToken() {
        @Override
        public boolean isCancellationRequested() {
            return false;
        }

        @NonNull
        @Override
        public CancellationToken onCanceledRequested(@NonNull OnTokenCanceledListener onTokenCanceledListener) {
            return this;
        }
    };

    private void reGetCurrentLocationAfter2000Millis() {
        try {
            if (mHandler != null) {
                mHandler.postDelayed(mGetCurrentLocationRunable, 5000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void reGetLastLocationAfter2000Millis() {
        try {
            if (mHandler != null) {
                mHandler.postDelayed(mGetLastLocationRunable, 5000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public interface OnLocationDidFetchedListener {
        void onLocationDidFetched(ASLocationInfoBean locationInfoBean);
    }

    class GetAddressTask extends AsyncTask<Location, Void, Address> {
        private Location mLocation;

        @Override
        protected Address doInBackground(Location... locations) {
            try {
                if (locations == null || locations.length == 0) {
                    return null;
                }
                Location loca = locations[0];
                mLocation = loca;
                Geocoder gc = new Geocoder(mContext, Locale.getDefault());
                List<Address> result = gc.getFromLocation(loca.getLatitude(), loca.getLongitude(), 1);

                if (result != null && result.size() > 0) {
                    return result.get(0);
                }else {
                    Log.d(TAG, "result is null or result.size == 0");
                }
                return null;

            } catch (Exception e) {
                Log.d(TAG, "get Address: error");
                return null;
            }
        }

        @Override
        protected void onPostExecute(Address address) {
            Log.d(TAG, "onPostExecute: success");
            try {
                if (address != null && mLocation != null) {
                    String mAddress = address.getAddressLine(0);
                    String mLongitude = mLocation.getLongitude() + "";
                    String mLatitude = mLocation.getLatitude() + "";

                    Log.d(TAG, "mAddress: " + mAddress);
                    Log.d(TAG, "mLongitude: " + mLongitude);
                    Log.d(TAG, "mLatitude: " + mLatitude);

                    String getLocalProvince = ASUtil.safeString(address.getAdminArea());//获取省份
                    String getLocalCity = ASUtil.safeString(address.getLocality());//获取城市
                    String getSubLocality = ASUtil.safeString(address.getSubLocality());//获取省份
                    String getFeatureName = ASUtil.safeString(address.getFeatureName());//获取省份
                    String getDetailAddress = ASUtil.safeString(address.getAddressLine(0));//获取省份

                    ASLocationInfoBean locationInfoBean = new ASLocationInfoBean();
                    locationInfoBean.setBorrowId("");
                    locationInfoBean.setToken(mToken);
                    locationInfoBean.setProvince(getLocalProvince);
                    locationInfoBean.setCity(getLocalCity);
                    locationInfoBean.setCounty(getSubLocality);
                    locationInfoBean.setStreet(getFeatureName);
                    locationInfoBean.setDetail(getDetailAddress);
                    locationInfoBean.setLongitude(mLocation.getLongitude() + "");
                    locationInfoBean.setLatitude(mLocation.getLatitude() + "");

                    //上报
                    if (mOnLocationDidFetchedListener != null) {
                        mOnLocationDidFetchedListener.onLocationDidFetched(locationInfoBean);
                    }
                }
                else {
                    if(address==null) {
                        Log.d(TAG, "address==null");
                    }
                    if(mLocation==null) {
                        Log.d(TAG, "mLocation==null");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
